﻿#include <learn/painter/paint_ctx.h>

using namespace xi;
using namespace xi::painter;

Paint_Context::Paint_Context(int width, int height, std::function<void(const Paint_Context *)> initProc,
                             std::function<void(const Paint_Context *)> dealProc)
    : m_painter(new Painter3D(width, height)), m_aisContext(new AIS_Context(width, height)), m_initProc(initProc),
      m_dealProc(dealProc)
{
    // 起始转动到顶视图
    m_aisContext->info()->camera->top_view();

    // 注册渲染器
    m_aisContext->renderer_factory()->register_product("AIS_Mesh", [this]() { return new Mesh_Renderer(this); });

    // 生成默认纹理构造
    load_tex2d(Texture::Green2d);
    load_tex2d(Texture::White2d);
    load_tex2d(Texture::Black2d);
    load_tex2d(Texture::Chess);
}

void Paint_Context::gen_shader(std::string i, std::shared_ptr<Shader> shader)
{
    if (m_shaders.find(i) != m_shaders.end())
        return;

    m_shaders[i] = shader;
}

bool Paint_Context::bind_shader(std::string i)
{
    auto it = m_shaders.find(i);
    if (it == m_shaders.end())
    {
        std::cerr << "Program don't exist." << std::endl;
        return false;
    }

    m_current.shader = it->second;
    return true;
}

void Paint_Context::gen_array(int i)
{
    m_VAOs[i] = VAO{};
    m_VBOs[i] = VBO{};
    m_EBOs[i] = EBO{};
}

bool Paint_Context::bind_array(int i)
{
    auto it = m_VAOs.find(i);
    if (it == m_VAOs.end())
    {
        std::cerr << "Array don't exist." << std::endl;
        return false;
    }

    m_current.vao = m_VAOs[i];
    m_current.vbo = m_VBOs[i];
    m_current.ebo = m_EBOs[i];
    return true;
}

void Paint_Context::load_tex2d(const char *file)
{
    TGA_Image img;
    img.read_tga_file(file);
    m_textures.emplace_back(img);
}

void Paint_Context::load_tex2d(Texture texture)
{
    float rgba[] = {0, 0, 0, 1};

    switch (texture)
    {
    case Texture::Yellow2d:
        rgba[0] = rgba[1] = 1;
        break;
    case Texture::Red2d:
        rgba[0] = 1;
        break;
    case Texture::Green2d:
        rgba[1] = 1;
        break;
    case Texture::Blue2d:
        rgba[2] = 1;
        break;
    case Texture::White2d:
        rgba[0] = rgba[1] = rgba[2] = 1;
        break;
    case Texture::Black2d:
    case Texture::Chess:
        break;
    default:
        std::cerr << "Texture don't exists." << std::endl;
        break;
    }

    TGA_Color color(rgba[0] * 255, rgba[1] * 255, rgba[2] * 255, rgba[3] * 255);
    TGA_Image img(16, 16, TGA_Image::RGBA);

    for (int i = 0; i < 16; i++)
    {
        for (int j = 0; j < 16; j++)
        {
            if (texture == Texture::Chess && (i + j) % 2 == 0)
                img.set(i, j, TGA_Color(1, 1, 1));
            else
                img.set(i, j, color);
        }
    }

    m_textures.emplace_back(img);
}

void Paint_Context::resize_event(int width, int height)
{
    m_painter->resize(width, height);
    m_aisContext->resize_event(width, height);
}

TGA_Image Paint_Context::paint_event() const
{
    // 初始化
    static bool initialize = [&]() {
        m_initProc(this);
        return true;
    }();

    // 处理进程
    if (m_dealProc)
        m_dealProc(this);

    m_aisContext->paint_event();

    return m_painter->frame();
}

Paint_Context::Current Paint_Context::current() const
{
    return m_current;
}

std::shared_ptr<AIS_Context> Paint_Context::context() const
{
    return m_aisContext;
}

std::shared_ptr<Painter3D> Paint_Context::painter() const
{
    return m_painter;
}